package com.road.yishi;

import java.lang.reflect.ParameterizedType;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.aeonbits.owner.Config;
import org.aeonbits.owner.ConfigFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.road.common.core.NetConfig;
import com.road.common.core.NetConfigXml;
import com.road.yishi.admincmd.AdminCmdMgr;
import com.road.yishi.base.Server;
import com.road.yishi.mina.codec.protobuf.ProtobufCodecFactory;

/**
 * @Description :
 * @FileName: BaseServer.java
 * @Author :WeiHui.Zhang
 * @Data : 2016年2月19日 下午6:37:43
 * @Version:V1.00
 */
public abstract class BaseServer<T extends Config> implements Server {

	protected static final Logger LOGGER = LoggerFactory.getLogger(BaseServer.class);

	private long lastInitMillis;

	private T config;

	protected AdminCmdMgr adminCmdMgr;

	// private int id; // 服务器ID--作用：因为跨服和网关可以有多个，这个标示代表他是第几个，从而做一些处理

	private NioSocketAcceptor acceptor;

	@SuppressWarnings("unchecked")
	public BaseServer() {
		ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
		// System.out.println((Class<T>)(parameterizedType.getActualTypeArguments()[0]));
		this.config = ConfigFactory.create((Class<T>) (parameterizedType.getActualTypeArguments()[0]));
	}

	public T getConfig() {
		return config;
	}

	@Override
	public boolean start() {
		lastInitMillis = System.currentTimeMillis();

		// 网关配置
		if (!initComponent(NetConfig.init(getGlobalFilePath(), getCrossFilePath()), "服务器配置信息")) {
			return false;
		}

		return true;
	}

	protected abstract String getGlobalFilePath();

	protected abstract String getCrossFilePath();

	protected abstract String getScanPackage();

	// 服务器ID--作用：因为跨服和网关可以有多个，这个标示代表他是第几个，从而做一些处理
	protected abstract int getServerId();

	@Override
	public boolean stop() {
		return true;
	}

	protected boolean initMina(IoHandlerAdapter serverHandler, int type) {
		NetConfigXml netXml = NetConfig.getNetConfigXml(type, getServerId());
		if (netXml == null) {
			LOGGER.error("Can not found socket config info, server will start failed.");
			return false;
		}

		try {
			acceptor = new NioSocketAcceptor(Runtime.getRuntime().availableProcessors() + 1);// 准备可接受IO通道
			acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ProtobufCodecFactory()));
			acceptor.getFilterChain().addLast("executor", new ExecutorFilter(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2 + 1)));
			SocketSessionConfig config = acceptor.getSessionConfig();// 对通道的一些设置
			config.setSendBufferSize(4096);
			config.setReadBufferSize(4096);
			config.setIdleTime(IdleStatus.BOTH_IDLE, 10);
			config.setReuseAddress(false);
			config.setSoLinger(5);// 5秒
			config.setTcpNoDelay(true);
			acceptor.setHandler(serverHandler);
			acceptor.bind(new InetSocketAddress(netXml.getPort()));

			// GatewayLinkedSet.init(NetConfig.gatewayCount());
			
			initAdminCommand(netXml);

			LOGGER.info("启动服务器监听成功, port : {} , adminPort : {} 。", netXml.getPort(), netXml.getAdminPort());
			return true;
		} catch (Exception e) {
			LOGGER.error("启动服务器监听失败start server listening failed, port : " + netXml.getPort() + ", adminPort : " + netXml.getAdminPort(), e);
		}

		return false;
	}

	/**
	 * 初始化相关模块
	 * 
	 * @param initResult
	 * @param componentName
	 * @return
	 */
	public boolean initComponent(boolean initResult, String componentName) {
		if (!initResult) {
			LOGGER.error(componentName + "错误");
		} else {
			LOGGER.info(componentName + "加载完成.耗时 : " + (System.currentTimeMillis() - lastInitMillis) + " ms");
		}
		lastInitMillis = System.currentTimeMillis();
		return initResult;
	}

	protected void initAdminCommand(NetConfigXml netXml) {
		if (StringUtils.isNotBlank(getScanPackage())) {
			adminCmdMgr = new AdminCmdMgr(netXml, getScanPackage());
			adminCmdMgr.start();
			LOGGER.info("{} 后台管理模块启动成功！", netXml.getDesc());
		}
	}

	protected void stopWithJVMShutdown() {
		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					stop();
				} catch (Exception e) {
					LOGGER.error(e.getMessage(), e);
				}
			}
		}));
	}

}
